package araxy.blog.service.impl;

import araxy.blog.entity.PayloadDto;
import araxy.blog.entity.Token;
import araxy.blog.entity.User;
import araxy.blog.exception.TokenException;
import araxy.blog.mapper.TokenMapper;
import araxy.blog.mapper.UserMapper;
import araxy.blog.service.UserService;
import araxy.blog.utils.*;

import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@ResponseBody
public class UserServiceImpl implements UserService {
    @Resource
    UserMapper userMapper;

    @Override
    @Transactional
    public boolean addUser(String username,String password,String nickname) {
        return addUser(username,password,nickname,false);
    }

    @Override
    @Transactional
    public boolean addUser(String username,String password,String nickname,Boolean isAdministrator) {
        User user = new User();
        user.setId(UUIDUtil.getUUID());
        user.setUsername(username);
        user.setNickname(nickname);
        user.setPassword(MD5Util.getMD5(password));
        user.setAdminFlag(isAdministrator);
        int cnt = userMapper.insert(user);
        return cnt == 1;
    }

    @Override
    public Map<String,Object> loginAuth(Subject subject, UsernamePasswordToken usernamePasswordToken) {
        subject.login(usernamePasswordToken);
        Map<String,Object> map = new HashMap<>();
        map.put("flg",true);
        return map;
    }
    @Override
    public Object tokenAuth(String token) throws TokenException, JsonProcessingException {
        PayloadDto payloadDto = TokenUtil.verifyTokenByHMAC(token);
        if (payloadDto.getExp() < DateUtil.getSysTimeMS()) {
            throw new TokenException("token已过期");
        }
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()) {
            return JsonUtil.FlgTrueJSONString;
        }
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken();
        usernamePasswordToken.setUsername(payloadDto.getUsername());
        usernamePasswordToken.setPassword(payloadDto.getPassword().toCharArray());
        Map<String,Object> map = loginAuth(subject,usernamePasswordToken);
        if (payloadDto.getExp() - DateUtil.getSysTimeMS() < DateUtil.getDaysMS(3)) {
            payloadDto.setExp(DateUtil.getSysTimeMS() + DateUtil.getDaysMS(30));
            String token1 = TokenUtil.generateTokenByHMAC(payloadDto);
            Token t = new Token(token1,payloadDto.getUsername());
            map.put("token",t);
        }
        return map;
    }

    @Override
    public Object passwordAuth(String username,String password) throws JsonProcessingException {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        if (subject.isAuthenticated()) {
            return JsonUtil.FlgTrueJSONString;
        }
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken();
        usernamePasswordToken.setUsername(username);
        usernamePasswordToken.setPassword(MD5Util.getMD5(password).toCharArray());
        Map<String,Object> map = loginAuth(subject,usernamePasswordToken);
        PayloadDto payloadDto = TokenUtil.getPayloadDto(usernamePasswordToken.getUsername(),String.valueOf(usernamePasswordToken.getPassword()));
        String token = TokenUtil.generateTokenByHMAC(payloadDto);
        Token t = new Token(token,username);
        map.put("token",t);
        return map;
    }

    @Override
    public Integer countAllAdmin() {
        return userMapper.countAllAdmin();
    }

    @Override
    @Transactional
    public boolean updateUser(User user) {
        return userMapper.updateByPrimaryKey(user) == 1;
    }

    @Override
    public List<User> getAll() {
        return userMapper.selectAll();
    }
}
